package kubernetescli

import (
	"context"
	"encoding/base64"
	"errors"
	"strconv"
	"time"

	"github.com/Kindling-project/chaos-backend/api"
	"github.com/Kindling-project/chaos-backend/tools/wrapper"
	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
)

type stresschaos struct {
}

func (n *stresschaos) ToChaosVO(obj *interface{}) []api.Chaos {
	return wrapper.StressChaosToChaosVO(obj)
}

func (n *stresschaos) List() (interface{}, error) {
	if client == nil {
		return nil, errors.New("kube-client not intilized yet")
	}
	result := v1alpha1.StressChaosList{}
	err := client.
		Get().
		Resource("stresschaos").
		Do(context.Background()).
		Into(&result)
	return result, err
}

func (n *stresschaos) Create(vo *api.Chaos) (interface{}, error) {
	if client == nil {
		return nil, errors.New("kube-client not intilized yet")
	}

	n.DeleteAll()

	stresschaos := buildStressChaos(vo, defaultStressChaosParam)
	result := v1alpha1.StressChaos{}
	err := client.
		Post().
		Namespace(stresschaos.Namespace).
		Resource("stresschaos").
		Body(stresschaos).
		Do(context.Background()).
		Into(&result)
	return result, err
}

func (n *stresschaos) DeleteAll() (interface{}, error) {
	if client == nil {
		return nil, errors.New("kube-client not intilized yet")
	}

	result := v1alpha1.StressChaosList{}
	err := client.
		Get().
		Resource("stresschaos").
		Do(context.Background()).
		Into(&result)

	if err != nil {
		return nil, err
	}

	var lastChaos v1alpha1.StressChaos
	for _, chaos := range result.Items {
		if v, ok := chaos.Labels["kindling-chaos"]; ok && v == "train-ticket" {
			result := v1alpha1.StressChaos{}
			err := client.
				Delete().
				Resource("stresschaos").
				Name(chaos.Name).
				Namespace(chaos.Namespace).
				Do(context.Background()).Into(&result)
			if err != nil {
				return nil, err
			}
			lastChaos = chaos
		}
	}

	return lastChaos, err
}

var cpuload = 100
var defaultStressChaosParam = v1alpha1.StressChaos{
	Spec: v1alpha1.StressChaosSpec{
		Stressors: &v1alpha1.Stressors{
			CPUStressor: &v1alpha1.CPUStressor{
				Stressor: v1alpha1.Stressor{
					Workers: 4,
				},
				Load: &cpuload,
			},
			MemoryStressor: &v1alpha1.MemoryStressor{
				Stressor: v1alpha1.Stressor{
					Workers: 4,
				},
				Size: "256M",
			},
		},
	},
}

func buildStressChaos(vo *api.Chaos, params v1alpha1.StressChaos) *v1alpha1.StressChaos {
	var resource = params.DeepCopy()
	ts := time.Now().Unix()

	resource.Name = "stresschaos" + "-" + strconv.FormatInt(ts, 10)
	resource.Namespace = "train-ticket"
	// Mark labels
	resource.Labels = map[string]string{
		"kindling-chaos": "train-ticket",
	}
	resource.Annotations = map[string]string{
		"describe":       base64.URLEncoding.EncodeToString([]byte(vo.Desc)),
		"complex-action": base64.URLEncoding.EncodeToString([]byte(vo.ComplexAction)),
	}

	for i := 0; i < len(vo.Params); i++ {
		switch vo.Params[i].Name {
		case "action":
			switch vo.Params[i].Value {
			case "cpu":
				resource.Spec.Stressors.MemoryStressor = nil
			case "memory":
				resource.Spec.Stressors.CPUStressor = nil
			}
		case "instance":
			resource.Spec.Selector.LabelSelectors = map[string]string{
				"app": vo.Params[i].Value,
			}
			resource.Annotations["target"] = vo.Params[i].Value
			resource.Spec.Mode = v1alpha1.AllMode
		}
	}

	return resource
}
